package com.youxuan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youxuan.enums.AppHttpCodeEnum;
import com.youxuan.exception.SystemException;
import com.youxuan.mapper.UserMapper;
import com.youxuan.pojo.entity.LoginUser;
import com.youxuan.pojo.entity.ResponseFormat;
import com.youxuan.pojo.entity.ResponseResult;
import com.youxuan.pojo.entity.User;
import com.youxuan.pojo.vo.UserVo;
import com.youxuan.service.UserService;
import com.youxuan.util.BeanCopyUtils;
import com.youxuan.util.JwtUtil;
import com.youxuan.util.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserMapper userMapper;

    @Override
    public ResponseResult login(User user) {
        LoginUser loginUser = updateLogin(user);

        String jwt = JwtUtil.createJWT(loginUser.getUser().getId().toString());
        ResponseFormat.LoginFormat loginFormat = new ResponseFormat.LoginFormat();
        loginFormat.setToken(jwt);

        UserVo userVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserVo.class);
        loginFormat.setUserVo(userVo);

        return ResponseResult.okResult(loginFormat);
    }

    public LoginUser updateLogin(User user){
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        if (Objects.isNull(authenticate)){
            throw new SystemException(AppHttpCodeEnum.LOGIN_ERROR);
        }

        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String id = loginUser.getUser().getId().toString();

        redisCache.setCacheObject("youxuan:"+id,loginUser);
        return loginUser;
    }

    @Override
    public ResponseResult updatePassword(String oldPassword, String newPassword) {
        LoginUser loginUser = getLoginUser();

        if (!passwordEncoder.matches(oldPassword,loginUser.getPassword())) {
            throw new SystemException(AppHttpCodeEnum.PWD_ERROR);
        }

        String encode = passwordEncoder.encode(newPassword);

        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId,loginUser.getUser().getId());
        updateWrapper.set(User::getPassword,encode);
        userMapper.update(null,updateWrapper);

        updateLogin(new User(loginUser.getUsername(),newPassword));

        return ResponseResult.okResult();
    }


    private LoginUser getLoginUser() {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (Objects.isNull(loginUser)){
            throw new SystemException(AppHttpCodeEnum.NEED_LOGIN);
        }
        return loginUser;
    }


    @Override
    public ResponseResult logout() {
        LoginUser loginUser = getLoginUser();
        Long id = loginUser.getUser().getId();

        redisCache.deleteObject("youxuan:"+id);

        return ResponseResult.okResult();
    }

    @Override
    public UserVo getUserInfo(Long userId) {
        User user = userMapper.selectById(userId);
        return BeanCopyUtils.copyBean(user, UserVo.class);
    }


}
